package org.gitman.agentplatform.ui.graph;

import java.awt.BorderLayout;
import java.awt.Color;
import java.math.BigDecimal;
import java.math.RoundingMode;

import javax.swing.JPanel;
import javax.swing.JScrollPane;

import org.gitman.agentplatform.core.PlatformManager;
import org.gitman.agentplatform.ui.MainFrame;

import com.mxgraph.model.mxCell;
import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.util.mxConstants;
import com.mxgraph.util.mxRectangle;
import com.mxgraph.view.mxGraph;

public class GraphDisplPanel extends JPanel {
	
	private static double MIN_SCALE = 0.1;
	private static double MAX_SCALE = 3.0;
	private static double SCALE_STEP = 0.05;
				
	private PlatformManager platformManager;
	private GraphEditor graphEditor;
	private int size = 30;
	private mxGraph graph;
	private mxGraphComponent graphComponent;
	private Integer id = 0;
	private double scale = 1.0;
	

	public GraphDisplPanel(final MainFrame mainFrame){
		this.platformManager = PlatformManager.getInstatnce();
		this.graphEditor = GraphEditor.getInstance();
		graphEditor.setDisplay(this);
		
		setLayout(new BorderLayout());		
	}
	
	public mxGraphComponent getGraphComponent(){
		return graphComponent;
	}
	
	public void setGraphComponent(final mxGraphComponent graphComponent) {
		removeAll();
		add(graphComponent);
		setScale(1.0);
		this.graphComponent = graphComponent;
		graph = graphEditor.getGraph();
		graphComponent.getViewport().setBackground(Color.WHITE);
		graphComponent.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
		graphComponent.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
		GraphMouseAdapter adapter = new GraphMouseAdapter(this);
		graphComponent.getGraphControl().addMouseListener(adapter);
		graphComponent.getGraphControl().addMouseWheelListener(adapter);

		paintAll(getGraphics());
		
		
	}
	
	public Object insertVertex(int x, int y){
		Object v = null;
		graph.getModel().beginUpdate();
		try{
			String val = nextID();
			v = graphEditor.getGraph().insertVertex(graph.getDefaultParent(), val, val,  x, y, getDotSize(), getDotSize(), "defaultVertex;" + mxConstants.STYLE_SHAPE + "=" +  mxConstants.SHAPE_ELLIPSE);
		}finally{
			graph.getModel().endUpdate();
		}
		return v;
	}
	
	public Object insertEdge(Object from, Object to){
		Object e = null;
		graph.getModel().beginUpdate();
		try{
			e = graphEditor.getGraph().insertEdge(graph.getDefaultParent(), null, "",  from, to);
		}finally{
			graph.getModel().endUpdate();
		}		
		return e;
	}
	
	public int getDotSize(){
		return (int) (size*scale);
	}
	
	public double getScale() {
		return scale;
	}
	
	public void changeScale(int step){
		setScale(scale+SCALE_STEP*step);
	}
	
	private synchronized void setScale(double scale) {
		double prevScale = this.scale;
		if(scale > MAX_SCALE){
			this.scale = MAX_SCALE;
		}else if (scale < MIN_SCALE){
			this.scale = MIN_SCALE;
		}else{
			this.scale = scale;
		}
		if(this.scale != prevScale){
			System.out.println(scale);
			repaintGraph(prevScale);
		}
	}
	
	private synchronized void repaintGraph(double prevScale){
		for(Object o : graph.getChildVertices(graph.getDefaultParent())){
			mxCell cell = (mxCell) o;
			mxRectangle rectangle = graph.getCellBounds(cell);
			
			graph.resizeCell(cell, new mxRectangle(
					getCordinate(rectangle.getX(), prevScale, scale), 
					getCordinate(rectangle.getY(), prevScale, scale),
					getDotSize(), getDotSize() ));
		}
	}
	
	private double getCordinate(double coordinate, double prevScale, double currScale){
		BigDecimal c = new BigDecimal(coordinate);
		BigDecimal p = new BigDecimal(prevScale);
		BigDecimal s = new BigDecimal(currScale);
		
		return c.multiply(s).divide(p, 2, RoundingMode.HALF_UP).doubleValue();
	}
	
	
	private String nextID(){
		for(Object o : graph.getChildVertices(graph.getDefaultParent())){
			mxCell cell = (mxCell) o;
			int val = Integer.parseInt(cell.getValue().toString());
			if(val > id){
				id = val;
			}
		}
		id++;
		return id.toString();
	}
	
}
